from django import template
from django.utils.html import conditional_escape
from django.template.loader import render_to_string 
from django.db import models
from django.utils.encoding import smart_str, force_unicode
from django.contrib.admin.templatetags.admin_list import items_for_result
from django.utils.safestring import mark_safe
from django.contrib.admin.views.main import ORDER_VAR, ORDER_TYPE_VAR

register = template.Library()

class SubmitRowNode(template.Node): 
    def render(self, context): 
        app_label = context['app_label'] 
        opts = context['opts'] 
        change = context['change'] 
        is_popup = context['is_popup'] 
        save_as = context['save_as'] 
        context = { 
                   'onclick_attrib': (opts.get_ordered_objects() and change and 'onclick="submitOrderForm();"' or ''), 
                   'show_delete_link': (not is_popup and context['has_delete_permission'] and (change or context['show_delete'])), 
                   'show_save_as_new': not is_popup and change and save_as, 
                   'show_save_and_add_another': context['has_add_permission'] and not is_popup and (not save_as or context['add']),  
                   'show_save_and_continue': not is_popup and context['has_change_permission'], 'is_popup': is_popup, 
                   'show_save': True 
                   } 
        return render_to_string([ 
                                 "admin/%s/%s/submit_line.html" % (app_label, opts.object_name.lower()), 
                                 "admin/%s/submit_line.html" % app_label, 
                                 "admin/submit_line.html" 
                                 ], context) 
        
def submit_row(parser, token): 
    return SubmitRowNode() 
submit_row = register.tag(name="submit_row")(submit_row) 

class ResultList(template.Node):
    def result_headers(self, cl):
        lookup_opts = cl.lookup_opts
        
        for i, field_name in enumerate(cl.list_display):
            attr = None
            try:
                f = lookup_opts.get_field(field_name)
                admin_order_field = None
            except models.FieldDoesNotExist:
                # For non-field list_display values, check for the function
                # attribute "short_description". If that doesn't exist, fall back
                # to the method name. And __str__ and __unicode__ are special-cases.
                if field_name == '__unicode__':
                    header = force_unicode(lookup_opts.verbose_name)
                elif field_name == '__str__':
                    header = smart_str(lookup_opts.verbose_name)
                else:
                    if callable(field_name):
                        attr = field_name # field_name can be a callable
                    else:
                        try:
                            attr = getattr(cl.model_admin, field_name)
                        except AttributeError:
                            try:
                                attr = getattr(cl.model, field_name)
                            except AttributeError:
                                raise AttributeError, \
                                    "'%s' model or '%s' objects have no attribute '%s'" % \
                                        (lookup_opts.object_name, cl.model_admin.__class__, field_name)
                    
                    try:
                        header = attr.short_description
                    except AttributeError:
                        if callable(field_name):
                            header = field_name.__name__
                        else:
                            header = field_name
                        header = header.replace('_', ' ')
    
                # It is a non-field, but perhaps one that is sortable
                admin_order_field = getattr(attr, "admin_order_field", None)
                if not admin_order_field:
                    yield {"text": header,
                           "style_attrib":mark_safe(' style="%s"' % ' '. join([u'%s: %s ' % (k, conditional_escape(v)) for k, v in getattr(attr, 'attrs', {}).items()]) or ''),
                           "class_attrib":mark_safe(' class="%s"' % ' '. join(getattr(attr, 'css_class', [])) or '')}
                    continue
    
                # So this _is_ a sortable non-field.  Go to the yield
                # after the else clause.
            else:
                header = f.verbose_name
    
            th_classes = []
            new_order_type = 'asc'
            if field_name == cl.order_field or admin_order_field == cl.order_field:
                th_classes.append('sorted %sending' % cl.order_type.lower())
                new_order_type = {'asc': 'desc', 'desc': 'asc'}[cl.order_type.lower()]
    
            yield {"text": header,
                   "sortable": True,
                   "url": cl.get_query_string({ORDER_VAR: i, ORDER_TYPE_VAR: new_order_type}),
                   "class_attrib": mark_safe(th_classes and ' class="%s"' % ' '.join(th_classes) or '')}
    
    
    def results(self, cl):
        if cl.formset:
            for res, form in zip(cl.result_list, cl.formset.forms):
                yield list(items_for_result(cl, res, form))
        else:
            for res in cl.result_list:
                yield list(items_for_result(cl, res, None))
    
    def render(self, context):
        app_label = context['app_label'] 
        cl = context['cl']
        context = {'cl': cl,
                   'result_headers': list(self.result_headers(cl)),
                   'results': list(self.results(cl))
                   }
         
        return render_to_string([  
                                 "admin/%s/change_list_results.html" % app_label, 
                                 "admin/change_list_results.html", 
                                 ], context) 

        
def result_list(parser, token): 
    return ResultList() 
register.tag(name="result_list")(result_list) 
